#include "collide_coarse.h"

using namespace physics;

//////////////////////////////////////////
//			BoundingSphere				//
//////////////////////////////////////////
////////////////////////////////
// Constructor
// 
// Creates our bounding sphere using the passed properties
////////////////////////////////
BoundingSphere::BoundingSphere(const Vector3 &center, real radius)
{
	BoundingSphere::center = center;
	BoundingSphere::radius = radius;
}

////////////////////////////////
// Constructor
// 
// Creates a new sphere from the two passed spheres
////////////////////////////////
BoundingSphere::BoundingSphere(const BoundingSphere &one, const BoundingSphere &two)
{
	Vector3 centerOffset = two.center - one.center;
	real distance = centerOffset.squareMagnitude();
	real radiusDiff = two.radius - one.radius;

	// check if the larger sphere encloses the smaller one
	if (radiusDiff * radiusDiff >= distance)
	{
		if (one.radius > two.radius)
		{
			center = one.center;
			radius = one.radius;
		}
		else
		{
			center = two.center;
			radius = two.radius;
		}
	}

	// otherwise work with partially overlapping spheres
	else
	{
		distance = real_sqrt(distance);
		radius = (distance + one.radius + two.radius) * ((real)0.5);

		// the new center is based on one's center, moved 
		// towards two's center by an amount proportional 
		// to their radii

		center = one.center;
		if (distance > 0)
		{
			center += centerOffset * ((radius - one.radius) / distance);
		}
	}
}

////////////////////////////////
// overlaps
//
// determines if this sphere, and the passed sphere
// overlap with one another
////////////////////////////////
bool BoundingSphere::overlaps(const BoundingSphere *other) const
{
	real distanceSquared = (center - other->center).squareMagnitude();
	return distanceSquared < (radius + other->radius) * (radius + other->radius);
}

////////////////////////////////
// getGrowth
//
// Determines how much the sphere needs to grow (in radius) to 
// encapsulate the other
////////////////////////////////
real BoundingSphere::getGrowth(const BoundingSphere &other) const
{
	BoundingSphere newSphere(*this, other);

	// return a value proportional to the change in surface area;
	return newSphere.radius*newSphere.radius - radius*radius;
}